<script setup lang="ts" generic="T extends ViewCard">
import { /*vIntersectionObserver,*/ vElementHover, vResizeObserver } from '@vueuse/components'
import type { ViewCard } from './type'
import { getBottomDominantColor } from './utils'

const props = withDefaults(
  defineProps<{
    keyField?: string // 每一项的唯一标识的key, 默认id
    items: T[]
    scrollTop: number
    buffer?: number
    visibleHeight: number
    gutter?: number
    offsetTop?: number
    columnId?: number
    defaultItemHeight: number // 默认高度, 比如图片加载失败，无图片数据等时用到
    showDominantColor?: boolean
  }>(),
  {
    keyField: 'id',
    gutter: 0,
    buffer: 0,
    offsetTop: 0
  }
)

const emit = defineEmits<{
  updateItemDisplayHeight: [height: number, item: ViewCard]
}>()

const positions = computed(() => {
  const { keyField, items, gutter, offsetTop, defaultItemHeight } = props
  let top = offsetTop
  const arrs = items.map((item, index) => {
    const lastItem = items[index - 1]
    if (lastItem) {
      top = top + (lastItem.displayHeight || defaultItemHeight) + gutter
    }
    const height = gutter + item.displayHeight
    return {
      [props.keyField]: item[keyField] || index,
      height,
      top,
      bottom: top + height
    }
  })
  // if (props.columnId === 3) {
  //   console.log('arrs', arrs, gutter)
  // }
  // if (props.columnId === 3) {
  //   console.log('arrs', items, arrs)
  // }
  return arrs
})

const startIndex = computed(() => {
  let start = 0
  let end = positions.value.length - 1
  let index = -1

  while (start <= end) {
    const mid = Math.floor((start + end) / 2)
    const pos = positions.value[mid]
    // if (props.columnId === 3) {
    //   console.log('props.scrollTop.1', props.scrollTop, index, start, end, mid, pos)
    // }

    if (pos.bottom >= props.scrollTop) {
      index = mid
      end = mid - 1
    } else {
      start = mid + 1
    }
    // if (props.columnId === 3) {
    //   console.log('props.scrollTop.2', props.scrollTop, index, start, end, mid)
    // }
  }
  // if (props.columnId === 3) {
  //   console.log('props.scrollTop.3', props.scrollTop, index, end)
  // }

  return Math.max(0, index - props.buffer)
})

const endIndex = computed(() => {
  let currentHeight = 0
  let index = startIndex.value

  while (index < positions.value.length && currentHeight <= props.visibleHeight * 2) {
    currentHeight += positions.value[index].height
    index++
  }

  return Math.min(positions.value.length, index + props.buffer)
})

// 获取可视区域数据
const visibleItems = computed(() => {
  if (props.items.length === 0) return []

  // if (props.columnId === 3) {
  //   console.log('visibleItems', props.items.slice(startIndex.value, endIndex.value + 1))
  // }
  return props.items.slice(startIndex.value, endIndex.value + 1)
})

const currentPos = computed(() => {
  if (positions.value.length === 0 || visibleItems.value.length === 0) return 0
  const firstVisibleId = visibleItems.value[0][props.keyField]
  const currentPos = positions.value.find(item => item[props.keyField] === firstVisibleId)
  return currentPos
})

// 计算内容偏移量
const offset = computed(() => {
  return currentPos.value === 0 ? 0 : currentPos.value?.top
})

const getImageWithItem = (item: ViewCard) => {
  const itemCard = document.getElementById(
    `my-column-item-${item[props.keyField]}`
  ) as HTMLDivElement
  // const [img] = itemCard.getElementsByTagName('img')
  // console.log(1111111, itemCard.getElementsByTagName('img'))
  const img = itemCard?.querySelector('#my-water-fall-img-id')
  return img as HTMLImageElement
}

// const onIntersectionObserver = ([entrie]: IntersectionObserverEntry[], item: ViewCard) => {
//   const isVisible = entrie?.isIntersecting || false
//   const img = getImageWithItem(item)
//   if (img) {
//     isVisible
//       ? img.classList.add('my-water-fall-animation-show-item')
//       : img.classList.remove('my-water-fall-animation-show-item')
//   }
// }

const onResizeObserver = ([entrie]: ResizeObserverEntry[], item: ViewCard) => {
  const height = entrie.contentRect.height
  if (height) {
    // if (props.columnId === 3) {
    //   console.log('onResizeObserver', item, height)
    // }
    item.displayHeight = height
    emit('updateItemDisplayHeight', height, item)
  }
}

const onHover = async (hovered: boolean, item: ViewCard) => {
  const img = getImageWithItem(item)
  // console.log('hovered', hovered)
  if (img && hovered && !item.dominantColor && props.showDominantColor) {
    img.crossOrigin = 'crossorigin'
    item.dominantColor = await getBottomDominantColor(img)
    // loadImage(item.src).then(img => {
    //   item.dominantColor = calculateDominantColor(img)
    // })
  }
}

const totalHeight = computed(() => {
  return props.items.reduce((pre, cur) => {
    return pre + (cur.displayHeight || props.defaultItemHeight) + props.gutter
  }, 0)
})
</script>

<template>
  <!-- 占位元素 (模拟完整高度) -->
  <div :style="{ height: totalHeight + offsetTop + 'px' }" />
  <div
    class="visible-items"
    :style="{ gap: `${gutter}px`, transform: `translateY(${offset}px)` }"
  >
    <div
      v-for="item in visibleItems"
      :id="`my-column-item-${item[props.keyField]}`"
      :key="item[props.keyField]"
      v-element-hover="hovered => onHover(hovered, item)"
      v-resize-observer="entries => onResizeObserver(entries as any, item)"
      class="item card"
    >
      <!-- v-intersection-observer="entries => onIntersectionObserver(entries, item)" -->
      <!-- <div class="debug">
        <div>item index:{{ items.findIndex(a => a[props.keyField] === item[props.keyField]) }}</div>
        <div>
          item id:{{ item[props.keyField] }}- visibleHeight:{{ visibleHeight }}- scrollTop:{{
            scrollTop
          }}
        </div>
        <div>
          startIndex:{{ startIndex }}-endIndex:{{ endIndex }}-showCount:{{ visibleItems.length }}
        </div>
        <div>displayHeight:{{ item.displayHeight }}</div>
        <div>transform:{{ `translateY(${offset}px)` }}</div>
        <div>all items:{{ items.length }}</div>
        <div>
          item top:{{ positions.find(pos => pos[props.keyField] === item[props.keyField])?.top }}
        </div>
        <div>currentPos: {{ currentPos }}</div>
        <div>
          pos id:{{
            positions.find(pos => pos[props.keyField] === item[props.keyField])?.[props.keyField]
          }}
        </div>
        <div>scrollTop:{{ scrollTop }}</div>
      </div> -->
      <div
        :class="{ 'img-error-item': item.error }"
        :style="{ height: item.error ? `${defaultItemHeight}px` : undefined }"
      >
        <slot
          img-id="my-water-fall-img-id"
          :item="item"
          name="item"
        />
      </div>
    </div>
  </div>
</template>

<style lang="less">
.my-water-fall-animation-show-item {
  animation: scale-item 0.3s;
}

@keyframes scale-item {
  0% {
    scale: 0.9;
    opacity: 0.5;
  }

  100% {
    scale: 1;
    opacity: 1;
  }
}
</style>

<style lang="less" scoped>
.visible-items {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  width: 100%;
  flex: 1;
  flex-direction: column;

  .item {
    position: relative;
    background-color: #1f1f1f;
    border-radius: 4px;
    cursor: pointer;

    :deep(img) {
      display: block;
      object-fit: cover;
      width: 100%;
    }

    .img-error-item {
      // border: 10px solid red;
      box-sizing: border-box;
    }

    .debug {
      position: absolute;
      color: #fff;
      background-color: rgb(0 0 0 / 70%);
      z-index: 99;
      pointer-events: none;
    }
  }

  .card {
    display: flex;
    overflow: hidden;
    color: #000;
    flex-direction: column;
    // @bottom-mask-height: 40px;

    // &:hover {
    //   .content {
    //     height: var(--my-waterfall-bottom-content-height);
    //     transition: height 0.3s ease-out;
    //     transition-delay: 0.4s;

    //     .bottom-mask {
    //       transition-delay: 0.4s;
    //       height: @bottom-mask-height;
    //     }
    //   }
    // }

    // .content {
    //   --dominant-color: #0003;
    //   --dominant-color-1: #0003;

    //   position: relative;
    //   width: 100%;
    //   height: 0;
    //   // background: linear-gradient(to bottom, #0003, #0003), var(--dominant-color);
    //   background: var(--dominant-color);
    //   z-index: 9;
    //   transition: all 0.4s;
    //   // backdrop-filter: blur(180px);
    //   &.content-inner {
    //     position: absolute;
    //     bottom: 4px;
    //     right: 4px;
    //     left: 4px;
    //     width: initial;
    //     background: linear-gradient(
    //       to bottom,
    //       var(--dominant-color-1) 0%,
    //       var(--dominant-color),
    //       var(--dominant-color) 100%
    //     );

    //     .bottom-mask {
    //       display: none;
    //     }
    //   }

    //   .bottom-mask {
    //     position: absolute;
    //     pointer-events: none;
    //     top: calc(1px - 40px);
    //     right: 0;
    //     left: 0;
    //     height: 0;
    //     // backdrop-filter: blur(180px);
    //     background: linear-gradient(to bottom, transparent, var(--dominant-color));
    //     z-index: 9;
    //   }
    // }
  }
}
</style>
